﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using cc2530.Lib;
using cc2530.Lib.device;
using System.Net;

using cc2530.Lib.contiki;

namespace cc2530.Lib.device
{
    /*
        数据包转换方法:
     *                   icmpv6 option 字节：RCF4861  中有定义
     *                                    pc:6 字节mac              contiki : 8字节 EUI64地址  
     */

    /// <summary>
    /// 6lowpan 的 桥接实现 
    /// </summary>
    class bridge6lowpan:RawS2T
    {
        string prefix = "aaaa::";
        bool _isGetMac = false;
        System.Timers.Timer timer = new System.Timers.Timer(250);
        contikiNode _BorderRouter;
        /// <summary>
        /// 前缀,用于设置 border router 的 前缀
        /// </summary>
       public  String Prefix
        {
            get { return prefix; }
            set
            {
                try { IPAddress ip = IPAddress.Parse(value); prefix = value; }
                catch { prefix = "aaaa::"; }
            }
        }


        /// <summary>
        /// 事件，当 border 成功连接时发生
        /// </summary>
        public event Ulitily.onBorderRouterConnect onBorderRouterConnected;


        /// <summary>
        /// 构造 
        /// </summary>
        /// <param name="com"></param>
        /// <param name="tapkey"></param>
        public bridge6lowpan(String com,String tapkey):base(com,tapkey)
        {
            this.onTransationS2T += bridge6lowpan_onTransationS2T;
            this.onTransationT2S += bridge6lowpan_onTransationT2S;
            timer.Elapsed += timer_Elapsed;
        }


        /// <summary>
        /// open serial port
        /// </summary>
        /// <returns></returns>
        public int OpenSerialPort()
        {
           int r =  base.OpenSerialPort();
           if (this.IsSerialOpen) { this.timer.Start(); }
           return r;
        }

        /// <summary>
        /// 定时器处理,用于定时获得
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (this.IsSerialOpen)
            {
                //throw new NotImplementedException();
                if (_isGetMac) { this.timer.Stop(); }
                else
                {
                    byte[] b = new byte[2];
                    b[0] = (byte)'?'; b[1] = (byte)'M';
                    this.WriteSerialPort(b, 2);
                }
            }
            else { this.timer.Stop(); }
        }
        


        /// <summary>
        /// Tap to serial 的协议转换
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        TransationBase bridge6lowpan_onTransationT2S(object sender, TransationBase args)
        {
            if (this.IsSerialOpen){
                if (_isGetMac && _BorderRouter != null && args.datalen > 14)
                {
                    return  Tranformation.Tap2Serial(args);

                }
            }


            return null;
        }


        /// <summary>
        /// serial to Tap 的协议转换 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        TransationBase bridge6lowpan_onTransationS2T(object sender, TransationBase args)
        {
            try{
                if (args.datalen >= 2 && args.data[0] == (byte)'?' && args.data[1] == (byte)'P')
                {
                    args.data[0] = (byte)'!';
                    args.data[1] = (byte)'P';
                    byte[] address = IPAddress.Parse(this.prefix).GetAddressBytes();
                    Array.Copy(address, 0, args.data, 2, address.Length);
                    args.datalen = address.Length + 2;
                    this.WriteSerialPort(args.data,args.datalen);
                    return null;
                }
                else if (args.datalen >= 2 && args.data[0] == (byte)'!' && args.data[1] == (byte)'M')
                {
                    this._isGetMac = true;
                    /* Read gateway MAC address and autoconfigure tap0 interface */
                    byte[] RouteMac = new byte[8];
                    int i;
                    char left_c, right_c;
                    for (i = 0; i < 8; ++i)
                    {
                        left_c = (char)args.data[i * 2 + 2];
                        right_c = (char)args.data[i * 2 + 3];
                        RouteMac[i] = Convert.ToByte(left_c.ToString(), 16);
                        RouteMac[i] *= 16;
                        RouteMac[i] += Convert.ToByte(right_c.ToString(), 16);
                    }

                    //取得路由器地址
                    this._BorderRouter = new contikiNode(RouteMac);
                    this._BorderRouter.IP = (IPv6Address.IPv6IPAddressWithPrefix(prefix, 64, IPv6Address.ToEUI64(RouteMac)));              
                    this._BorderRouter.ntype = NodeType.BorderRouter;

                    ///事件
                    if (this.onBorderRouterConnected != null)
                    {
                        this.onBorderRouterConnected(this, this._BorderRouter);
                    }
                    return null;
                }

                if (_isGetMac && this._BorderRouter!=null) {


                    ///协议转换
                    return Tranformation.Serial2Tap(args,
                        _BorderRouter.Mac,
                        base.MyTap.GetMac());

                }

                return null;

            }catch (Exception e){
                System.Console.WriteLine(e.ToString());
                return args;
            }
        }

        /// <summary>
        /// is get border ??yet
        /// </summary>
        public bool IsGetBorderRouter { get { return this._isGetMac; } }


        /// <summary>
        /// Borderrouter
        /// </summary>
        public contikiNode BorderRouter { get { return this._BorderRouter; } }

        /// <summary>
        /// 重获borderrouter
        /// </summary>
        public void ReGetBorderRouter() {
            this._isGetMac = false;
            this.timer.Start();
            this._BorderRouter = null;
        }

    }
}
